package com.cdks.wuxiu.api.service.mysql;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cdks.wuxiu.api.component.constant.Constant;
import com.cdks.wuxiu.api.mapper.UserScoreInfoMapper;
import com.cdks.wuxiu.api.model.dto.UserScoreDTO;
import com.cdks.wuxiu.api.util.SmsUtils;
import com.cdks.wuxiu.api.util.TimeUtils;
import com.cdks.wuxiu.entity.mysql.UserScoreInfo;

import lombok.extern.slf4j.Slf4j;

import java.util.List;

import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 用户积分 服务实现类
 */
@Slf4j
@Service
public class UserScoreInfoServiceImpl extends ServiceImpl<UserScoreInfoMapper, UserScoreInfo> implements UserScoreInfoService {
    @Transactional
    @Override
    public UserScoreDTO getBalanceByUser(long userId, long expire) {
        UserScoreDTO  balance  = baseMapper.getBalance(userId, expire);
        if (balance.getCount() == 0)
        {
            balance.setMinId(0L);
            balance.setMaxId(0L);
            balance.setScore(0L);
        }

        return balance;
    }

    @Override
    public List<UserScoreInfo> getByUserId(long userId, int page, long start, long stop) {
        return baseMapper.getList(userId, start, stop, page * Constant.LIST_PAGE_SIZE, Constant.LIST_PAGE_SIZE);
    }

    @Transactional
    @Override
    public int decByUserId(long userId, long minId, long maxId, long cost, long now) {
        if (cost <= 0)
        {
            return 0;
        }

        QueryWrapper<UserScoreInfo> wrapper = new QueryWrapper<>();
        wrapper.lambda().eq(UserScoreInfo::getUserId, userId)
                        .eq(UserScoreInfo::getStatus, Constant.SCORE_STATUS_UNUSE)
                        .between(UserScoreInfo::getId, minId, maxId)
                        .gt(UserScoreInfo::getExpire, now)
                        .orderByAsc(UserScoreInfo::getExpire)
                        .orderByAsc(UserScoreInfo::getId);
        
        long count     = 0;
        long leftCost  = cost;
        UserScoreInfo lastScore  = null;
        List<UserScoreInfo> scoreList  = baseMapper.selectList(wrapper);
        for (UserScoreInfo score : scoreList)
        {
            if (leftCost > score.getUnuse())
            {
                //剩余需要扣除的费用大于当前积分，则当前积分应该全部扣除，先做标记，后面批量清零
                count ++;
                leftCost  = leftCost - score.getUnuse();

                continue;
            }
            else if (leftCost > 0)
            {
                //剩余需要扣除的费用不大于当前积分，并且剩余需要扣除的费用不为零，则说明当前积分有剩余。剩余的积分先保存然后等clean之后单独更新
                if (score.getUnuse() > leftCost)
                {
                    lastScore  = score;

                    lastScore.setStatus(Constant.SCORE_STATUS_UNUSE);
                    lastScore.setUnuse(score.getUnuse() - leftCost);
                }

                leftCost  = 0;
                count ++;
            }

            break;
        }

        if (count > 0)
        {
            //将需要完全扣除的积分项全部清零
            int ret  = baseMapper.cleanBalance(userId, minId, maxId, count, now);
            if (ret != count)
            {
                log.error("clean score failed: userId = " + userId  + ", id = [" + minId + ", " + maxId + "], count = " + count + ", ret = " + ret);
    
                //发送短信通知
                SmsUtils.sendManageNotice("积分扣除失败-1");

                return -1;
            }
        }

        if (lastScore != null)
        {
            int ret  = baseMapper.updateById(lastScore);
            if (ret == 0)
            {
                log.error("update score failed 1: userId = " + userId + ", cost = " + cost  + ", leftCost = " + leftCost  + ", id = [" + minId + ", " + maxId + "], ret = " + ret);

                //发送短信通知
                SmsUtils.sendManageNotice("积分扣除失败-2");

                return -2;
            }
        }

        //因为扣除积分之前已经计算过有多少积分可扣，所以剩余需要扣除的费用必然为0
        if (leftCost != 0)
        {
            log.error("update score failed 2: userId = " + userId + ", cost = " + cost  + ", leftCost = " + leftCost  + ", id = [" + minId + ", " + maxId + "]");

            //发送短信通知
            SmsUtils.sendManageNotice("积分扣除失败-3");

            return -3;
        }

        return 0;
    }

    @Override
    public int addScore(long userId, long score, int type, long expire, String remark)
    {
        UserScoreInfo info  = new UserScoreInfo();
        info.setCreateTime(TimeUtils.getTimeSecond());
        info.setExpire(expire);
        info.setRemark(remark);
        info.setScore(score);
        info.setUnuse(score);
        info.setType(type);
        info.setUserId(userId);

        int ret  = baseMapper.insert(info);
        if (ret > 0)
        {
            return ret;
        }

        log.error("add score failed: info=" + info + "ret=" + ret);

        return -1;
    }
}
